package com.flyqiu.common.single;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;

/**
 * 飞秋单例工厂类，用于创建和获取单例对象。
 */
@Slf4j
public class FlyQiuSingletonFactory {
    // 设置最大容量为1024，可根据实际情况调整
    private static int CACHE_CAPACITY = 1024;

    private static final LinkedHashMap<String, FlyQiyBaseSingleton> cache = new LinkedHashMap<>(16, 0.75f, true) {
        protected boolean removeEldestEntry(Map.Entry eldest) {
            return size() > CACHE_CAPACITY;
        }
    };

    /**
     * 设置缓存数据容量。
     *
     * @param capacity 缓存容量
     */
    public static void setCacheCapacity(int capacity) {
        if (capacity < 1) {
            throw new RuntimeException("缓存容量必须大于等于1");
        }
        CACHE_CAPACITY = capacity;
    }

    /**
     * 获取指定类的单例对象。
     * 如果该类的单例对象已存在，则直接返回；否则，创建新的单例对象并返回。
     *
     * @param clazz 需要获取单例对象的类
     * @param <T>   泛型，继承自FlyQiyBaseSingleton的类型
     * @return 返回该类的单例对象
     */
    @SuppressWarnings("unchecked")
    public static <T extends FlyQiyBaseSingleton> T get(Class<T> clazz) {
        return get(clazz, FlyQiuSingletonFactory::defaultLoaderInstance);
    }

    /**
     * 获取指定类的单例对象。
     * 如果该类的单例对象已存在，则直接返回；否则，使用提供的加载器创建新的单例对象并返回。
     *
     * @param clazz 需要获取单例对象的类
     * @param loader 单例对象的加载器
     * @param <T>   泛型，继承自FlyQiyBaseSingleton的类型
     * @return 返回该类的单例对象
     */
    public static <T extends FlyQiyBaseSingleton> T get(Class<T> clazz, Function<Class<T>, T> loader) {
        if (clazz == null) {
            throw new IllegalArgumentException("类不能为空");
        }
        if (loader == null) {
            throw new IllegalArgumentException("加载器不能为空");
        }
        String key = clazz.getName();
        log.debug("尝试获取单例对象: {}", key);

        // 检查缓存中是否已有该类的单例对象
        T flyQiyBaseSingleton = getCacheInstance(key, clazz);
        if (flyQiyBaseSingleton != null) {
            log.debug("从缓存中找到单例对象: {}", key);
            return flyQiyBaseSingleton;
        }
        synchronized (clazz) {
            flyQiyBaseSingleton = getCacheInstance(key, clazz);
            if (flyQiyBaseSingleton != null) {
                log.debug("从缓存中找到单例对象: {}", key);
                return flyQiyBaseSingleton;
            }

            log.debug("创建新的单例对象: {}", key);
            flyQiyBaseSingleton = loader.apply(clazz);
            cache.put(key, flyQiyBaseSingleton);
        }

        try {
            flyQiyBaseSingleton.flyQiyInit();
            log.debug("单例对象初始化成功: {}", key);
        } catch (Exception e) {
            log.error("单例对象初始化失败: {}", key, e);
            cache.remove(key, flyQiyBaseSingleton);
            throw new RuntimeException("单例对象初始化失败", e);
        }

        return flyQiyBaseSingleton;
    }

    /**
     * 从缓存中获取指定类的单例对象。
     *
     * @param key 缓存键
     * @param clazz 类
     * @param <T> 泛型，继承自FlyQiyBaseSingleton的类型
     * @return 返回该类的单例对象
     */
    private static <T> T getCacheInstance(String key, Class<T> clazz) {
        FlyQiyBaseSingleton baseSingleton = cache.get(key);
        if (baseSingleton == null) {
            return null;
        }
        return clazz.cast(baseSingleton);
    }

    /**
     * 使用默认加载器创建新的单例对象。
     *
     * @param clazz 类
     * @param <T> 泛型，继承自FlyQiyBaseSingleton的类型
     * @return 返回新的单例对象
     */
    private static <T extends FlyQiyBaseSingleton> T defaultLoaderInstance(Class<T> clazz) {
        try {
            // 使用反射创建新的单例对象
            Constructor<T> constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(true);
            return constructor.newInstance();
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            log.error("创建单例对象失败: {}", clazz.getName(), e);
            throw new RuntimeException("创建单例对象失败", e);
        }
    }

    /**
     * 移除指定类的单例对象。
     *
     * @param clazz 需要移除单例对象的类
     */
    public void remove(Class<? extends FlyQiyBaseSingleton> clazz) {
        String key = clazz.getName();
        log.debug("移除单例对象: {}", key);
        cache.remove(key);
    }
}
